from selenium.webdriver.support.select import Select
class PageElement:

    def __init__(self, **locator):
        if not locator:
            raise ValueError('必须指定一个定位器')
        if len(locator) > 1:
            raise ValueError('只能有一个定位器')
        self.locator = locator
        self.k,self.v = next(iter(locator.items()))#这里用了一个迭代器，字典是一个可迭代对象

    def __get__(self, instance, owner):#利用描述符自动传入driver
        if instance is None:
            return None
        self.__driver = instance.driver
        return self

    def clear(self):
        element = self.__get_element()
        element.clear()
        
    def send_keys(self,value):
        element = self.__get_element()
        element.send_keys(value)

    def click(self):
        element = self.__get_element()
        element.click()

    def submit(self):
        element = self.__get_element()
        element.submit()

    def __get_element(self):
        return self.__driver.find_element(self.k,self.v)

    def select_by_value(self, value):
        element = self.__get_element()
        Select(element).select_by_value(value)

    def select_by_index(self, index):
        element = self.__get_element()
        Select(element).select_by_index(index)

    def select_by_visible_text(self, text):
        element = self.__get_element()
        Select(element).select_by_visible_text(text)


    @property
    def tag_name(self):
        """This element's ``tagName`` property."""
        elem = self.__get_element()
        return elem.tag_name

    @property
    def text(self):
        """Clears the text if it's a text entry element."""
        elem = self.__get_element()
        return elem.text

    @property
    def size(self):
        """The size of the element."""
        elem = self.__get_element()
        return elem.size

    def get_property(self, name):
        """
        Gets the given property of the element.
        """
        elem = self.__get_element()
        return elem.get_property(name)

    def get_attribute(self, name):
        """Gets the given attribute or property of the element."""
        elem = self.__get_element()
        return elem.get_attribute(name)

    def is_displayed(self):
        """Whether the element is visible to a user."""
        elem = self.__get_element()
        return elem.is_displayed()

    def is_selected(self):
        """Returns whether the element is selected.

        Can be used to check if a checkbox or radio button is selected.
        """
        elem = self.__get_element()
        return elem.is_selected()

    def is_enabled(self):
        """Returns whether the element is enabled."""
        elem = self.__get_element()
        return elem.is_selected()

    def switch_to_frame(self):
        """
        selenium API
        Switches focus to the specified frame
        """
        elem = self.__get_element()
        Browser.driver.switch_to.frame(elem)

    def move_to_element(self):
        """
        selenium API
        Moving the mouse to the middle of an element
        """
        elem = self.__get_element()
        ActionChains(Browser.driver).move_to_element(elem).perform()

    def click_and_hold(self):
        """
        selenium API
        Holds down the left mouse button on an element.
        """
        elem = self.__get_element()
        ActionChains(Browser.driver).click_and_hold(elem).perform()

    def context_click(self):
        """
        selenium API
        Performs a context-click (right click) on an element.
        """
        elem = self.__get_element()
        ActionChains(Browser.driver).context_click(elem).perform()

    def drag_and_drop_by_offset(self, x, y):
        """
        selenium API
        Holds down the left mouse button on the source element,
           then moves to the target offset and releases the mouse button.
        :param x: X offset to move to.
        :param y: Y offset to move to.
        """
        elem = self.__get_element()
        ActionChains(Browser.driver).drag_and_drop_by_offset(elem, xoffset=x, yoffset=y).perform()

    def refresh_element(self, timeout=10):
        """
        selenium API
        Refreshes the current page, retrieve elements.
        """
        try:
            timeout_int = int(timeout)
        except TypeError:
            raise ValueError("Type 'timeout' error, must be type int() ")

        elem = self.__get_element()
        for i in range(timeout_int):
            if elem is not None:
                try:
                    elem
                except StaleElementReferenceException:
                    Browser.driver.refresh()
                else:
                    break
            else:
                sleep(1)
        else:
            raise TimeoutError("stale element reference: element is not attached to the page document.")
